/*
 * HashRecord.cpp
 *
 *  Created on: Oct 2, 2011
 *      Author: Belen
 */
#include "HashRecord.h"

unsigned long HashRecord::size() {
	return blocksFile->getBlocksCount();
}

bool HashRecord::getBlockByBlockId(unsigned long id,Block** block) {
	return blocksFile->getBlockById(id,block);
}

unsigned long HashRecord::getRecordPosition(unsigned long idBlock,unsigned long regKey) {

	unsigned long cantRegs = -1;
	Block*	block = NULL;
	unsigned long found = -1;

	/* TODO: REMOVER
	if (regKey == 1112255) {
		cout << "getRecordPosition: 1112255 -  blockId" << idBlock <<endl;
	}
*/

	if (blocksFile->getBlockById(idBlock,&block)==false){
		return -1;
	}

	cantRegs = block->getRecordCount();

	//cout << "cant regs. " << cantRegs << endl;

	/* TODO: REMOVER
	if (regKey == 1112255) {
		cout << "cantRegs: " << cantRegs << endl;
	}
*/
	for (unsigned long i=0;i<cantRegs;i++) {
		//TODO:comparar bien los valores
		//char* entityWithId = new char [longEntity + sizeof(unsigned long)];

		//cout << "Reg: " << i << endl;

		// obtengo recordId;
		char*	record = NULL;
		unsigned long recordSize = -1;
		unsigned long recordKey = -1;

		if (block->getRecord(i,&record,&recordSize)) {

			char*p = reinterpret_cast<char*>(&recordKey);
			for (unsigned long j = 0 ; j < sizeof(unsigned long); j++) {
				*p = record[j];
				p++;
			}

			/* TODO: REMOVER
			if (regKey == 1112255) {
				cout << "recordKey: " << recordKey << endl;
			}
*/

			if(regKey == recordKey) {
				found = i;
				break;
			}
		}
	}

	/* TODO: REMOVER
	if (regKey == 1112255) {
		cout << "End" << endl;
	}
*/
	return found;
}

bool HashRecord::getRecord(unsigned long idBlock,unsigned long regKey, char** data, unsigned long* data_len){

	unsigned long cantRegs = -1;
	Block*	block = NULL;
	bool found = false;

	//cout << "idBlock " << idBlock << " - " << "regKey " << regKey << endl;

	unsigned long recordPosition = getRecordPosition(idBlock,regKey);

	//cout << "RecordPosition " << recordPosition << endl;

	if (recordPosition == -1)
		return false;

	if ((*data) != NULL) {
		return false;
	}

	if (blocksFile->getBlockById(idBlock,&block)==false){
		return false;
	}
	
	char* record = NULL;
	unsigned long recordSize = -1;
	unsigned long recordKey = -1;

	if (block->getRecord(recordPosition,&record,&recordSize)) {

		char*p = reinterpret_cast<char*>(&recordKey);
		for (unsigned long j = 0 ; j < sizeof(unsigned long); j++) {
			*p = record[j];
			p++;
		}

		if(regKey == recordKey) {
			(*data) = new char[recordSize - sizeof(unsigned long)];
			memcpy(*data,record+sizeof(unsigned long),recordSize - sizeof(unsigned long));
			(*data_len) = recordSize - sizeof(unsigned long);
			found = true;
		}
	}
	return found;
}

bool HashRecord::removeRecord(unsigned long blockNumber,unsigned long key){
	Block* block = NULL;
	unsigned long position = -1;
	
	if(blocksFile->getBlockById(blockNumber,&block) == false)
		return false;
	
	position = getRecordPosition(blockNumber,key);
	
    if (block->deleteRecord(position) == false)
    	return false;

    return blocksFile->updateBlock(block);
}

bool HashRecord::removeAllRecordsFromBlock(unsigned long blockNumber) {

	Block *oldBlock=NULL;

	if (blocksFile->getBlockById(blockNumber,&oldBlock) == false)
		return false;

	oldBlock->emptyBlock();

	return blocksFile->updateBlock(oldBlock);
}

bool HashRecord::getCopyOfBlock(unsigned long blockNumber,Block **block) {

	Block *oldBlock=NULL;

	if (blocksFile->getBlockById(blockNumber,&oldBlock) == false)
		return false;

	(*block) = new Block(oldBlock->getRawBlock(),blockSize);

	return true;
}

bool HashRecord::getNewBlock(unsigned long* newBlockNumber) {
	Block *block = NULL;

	if (blocksFile->getEmptyBlock(&block) == false)
		return false;

	(*newBlockNumber) = block->getId();

	return true;
}

bool HashRecord::addRecord(unsigned long idBlock, unsigned long idEntity, 
						   char* entity, unsigned long longEntity)
{	
	/* TODO: REMOVER
	if (idEntity == 1112255) {
		cout << "clave 1112255 en addRecord" << endl;
	}
*/

	Block* block = NULL;
	char* entityWithId = new char [longEntity + sizeof(unsigned long)];
	
	blocksFile->getBlockById(idBlock,&block);
	
	if(block->getFreeSpace() >= longEntity+ sizeof(unsigned long)){

		/* TODO: REMOVER
		if (idEntity == 1112255) {
			cout << "Espacio Libre: " << block->getFreeSpace() << " -- ";
			cout << "Tamanio Reg: "<< (longEntity+sizeof(unsigned long)) << endl;
		}
*/

		char*p = reinterpret_cast<char*>(&idEntity);
		for (unsigned long j = 0 ; j < sizeof(unsigned long); j++) {
			entityWithId[j] = *p;
			p++;
		}

		memcpy(entityWithId+sizeof(unsigned long),entity,longEntity);

		//TODO ACA ESTABA EL ERROR!!!
		bool res = block->addRecord(entityWithId,longEntity + sizeof(unsigned long));

		delete entityWithId;

		if (res == false) {
			//cout << "No se pudo agregar el registro al bloque" <<endl;
			return false;
		}

		res = (blocksFile->updateBlock(block));

		/* TODO: REMOVER
		if (idEntity == 1112255) {
			cout << "Actualizando en el bloque " << block->getId() << " :" << res<<endl;
		}
*/

		return res;
	}	

	/* TODO: REMOVER
	if (idEntity == 1112255) {
		cout << "addRecord 1112255 no ingresado" << endl;
	}
*/

	return false;
}

bool HashRecord::updateRecord(unsigned long idBlock, unsigned long regKey, char* entity, unsigned long longEntity){

	unsigned long idEntity = getRecordPosition(idBlock,regKey);
	
	if (idEntity == -1) {
		// call put o devuelve false
		return false;
	}
	else {
		Block* block = NULL;
		blocksFile->getBlockById(idEntity,&block);

		block->deleteRecord(idEntity);
		if(block->getFreeSpace()>=longEntity){
			return (block->addRecord(entity,longEntity));
		}
		else
			return false;
	}
}

HashRecord::HashRecord(string xFilePath,unsigned long xBlockSize) {
	blockSize = xBlockSize;
	filePath = xFilePath;
	blocksFile = new BlocksFile(filePath,blockSize);
}

HashRecord::~HashRecord() {
}
